

#include "GLFont.h"
#include <algorithm>
#include <boost/bind.hpp>
#include <boost/filesystem.hpp>
#include <FTGL/ftgl.h>
#include <GL/glu.h>

std::string get_ttf_path( const char* name )
{
	namespace fs = boost::filesystem;
	fs::path path(name);
	if( fs::exists(path) )
		return path.generic_string();
	std::vector< fs::path > sypaths;
	sypaths.push_back(fs::path("c:/fonts/"));
	sypaths.push_back(fs::path("c:/windows/fonts"));
	sypaths.push_back(fs::path("c:/winnt/fonts"));
	sypaths.push_back(fs::path("/usr/share/fonts/gnu-free"));

	boost::filesystem::path gap_path( std::getenv("Gallop_PATH") );
	sypaths.push_back(gap_path/"fonts");

	for( int i=0; i < sypaths.size(); i++ )
	{
		sypaths[i] /= path;
		if( fs::exists(sypaths[i]) )
			return sypaths[i].generic_string();
	}
	return path.generic_string();
}

GLFONT::GLFONT(void){
}

GLFONT::~GLFONT(void){
}

bool GLFONT::FaceSize(const unsigned int size,const unsigned int res){
	return ftFont_->FaceSize(size,res);
}

unsigned int GLFONT::FaceSize() const
{
	return ftFont_->FaceSize();
}

void GLFONT::Depth(float depth)
{
	return ftFont_->Depth(depth);
}

void GLFONT::Outset(float outset)
{
	return ftFont_->Outset(outset);
}
void GLFONT::Outset(float front, float back)
{
	return ftFont_->Outset(front,back);
}

void GLFONT::UseDisplayList(bool useList)
{
	return ftFont_->UseDisplayList(useList);
}

float GLFONT::Ascender() const
{
	return ftFont_->Ascender();
}

float GLFONT::Descender() const
{
	return ftFont_->Descender();
}
float GLFONT::LineHeight() const
{
	return ftFont_->LineHeight();
}
void GLFONT::BBox(const char* string, float& llx, float& lly, float& llz,
                  float& urx, float& ury, float& urz) const
{
	return ftFont_->BBox(string,llx,lly,llz,urx,ury,urz);
}

void GLFONT::renderText(double x,double y, double z, const char* str) const
{
	glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT );
		glShadeModel(GL_SMOOTH); // 启用阴影平滑
	    glClearDepth(1.0f); // 设置深度缓存
	    glEnable(GL_DEPTH_TEST); // 启用深度测试
	    glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
	    glEnable(GL_POINT_SMOOTH);//����������	
		glEnable(GL_LINE_SMOOTH);
		//glEnable(GL_MULTISAMPLE);
		glDisable(GL_LIGHTING);
	    glRasterPos3f(x,y,z);
		ftFont_->Render(str,-1);
	glPopAttrib();
}

void GLFONT::renderText(double x,double y, double z, const char* str,int haligned, int valigned) const
{
	FTPoint pt(0,0,0);
	if(ftFont_ && (haligned>0 || valigned>0)){
		float llx,lly,llz,urx,ury,urz;
		ftFont_->BBox(str,llx,lly,llz,urx,ury,urz);
		if(haligned==1){
			pt.X(-llx-(urx-llx)/2.0);
		}else if(haligned==2){
			pt.X(-urx);
		}
		if(valigned==1){
			pt.Y(-lly-(ury-lly)/2.0);
		}else if(valigned==2){
			pt.Y(-ury);
		}
	}

	glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT  | GL_ENABLE_BIT | GL_TRANSFORM_BIT);
		glShadeModel(GL_SMOOTH); // 启用阴影平滑
		glClearDepth(1.0f); // 设置深度缓存
		glEnable(GL_DEPTH_TEST); // 启用深度测试
		glDepthFunc(GL_LEQUAL); // 所作深度测试的类型
		glEnable(GL_POINT_SMOOTH);//����������
		glEnable(GL_LINE_SMOOTH);
		glDisable(GL_LIGHTING);
	    glRasterPos3f(x,y,z);
		ftFont_->Render(str,-1,pt);
	glPopAttrib();
}

void GLFONT::renderText(double x,double y, double z, const std::string& str) const{
	renderText(x,y,z,str.c_str());
}

void GLFONT::renderText(double x,double y,double z,const std::string& str,int haligned, int valigned) const
{
	renderText(x,y,z,str.c_str(),haligned,valigned);
}

void GLFONT::renderTextOnScreenCoord(double x,double y,const std::string& str,int haligned, int valigned) const{
	FTPoint pt(0,0,0);
	if(ftFont_ && (haligned>0 || valigned>0)){
		float llx,lly,llz,urx,ury,urz;
		ftFont_->BBox(str.c_str(),llx,lly,llz,urx,ury,urz);
		if(haligned==1){
			pt.X(-llx-(urx-llx)/2.0);
		}else if(haligned==2){
			pt.X(-urx);
		}
		if(valigned==1){
			pt.Y(-lly-(ury-lly)/2.0);
		}else if(valigned==2){
			pt.Y(-ury);
		}
	}
	renderTextOnScreenCoord(x+pt.X(),y+pt.Y(),str);
}

void GLFONT::renderTextOnScreenCoord(double x,double y, const std::string& str) const
{
	renderTextOnScreenCoord(x,y,str.c_str());
}

/// A fairly straight forward function that pushes
/// a projection matrix that will make object world 
/// coordinates identical to window coordinates.
inline void pushScreenCoordinateMatrix() {
	glPushAttrib(GL_TRANSFORM_BIT);
	GLint	viewport[4];
	glGetIntegerv(GL_VIEWPORT, viewport);
	glMatrixMode(GL_PROJECTION);
	glPushMatrix();
	glLoadIdentity();
	gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);
	glPopAttrib();
}

/// Pops the projection matrix without changing the current
/// MatrixMode.
inline void pop_projection_matrix() {
	glPushAttrib(GL_TRANSFORM_BIT);
	glMatrixMode(GL_PROJECTION);
	glPopMatrix();
	glPopAttrib();
}


void GLFONT::renderTextOnScreenCoord(double x,double y,const char* str) const
{
	pushScreenCoordinateMatrix();
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();
		renderText(x,y,0,str);
	pop_projection_matrix();
}
